package cpu;

import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;

import processes.Calc;
import processes.Consumer;
import processes.Process;
import processes.Producer;
import processes.UI;
import schedule.ScheduleType;
import schedule.Scheduler;
import schedule.SystemTimer;

public class CPU implements Runnable {
	public static int context_switch;
	public static int shared_mem;
	public static boolean ui_interrupt;

	private String my_reason = "";

	@Override
	public void run() {
		List<Process> procs = getProcesses();
		ScheduleType type = getSchedType();
		if (type == ScheduleType.PRIORITY)
		{
			getPriorities(procs);
		}
		Scheduler sched = new Scheduler(type, procs);

		Integer t = 10;
		SystemTimer st = new SystemTimer(t);
		st.setTimer();
		int index = 0;
		List<String> instrs;
		while (true) {
			CPU.context_switch = 0;
			Process p = sched.contextSwitch(my_reason);
			instrs = p.getInst();
			index = p.getIndex();
			while (CPU.context_switch == 0) {
				String output = instrs.get(index);
				index++;
				index = index % Process.INST_SIZE;
				
				if (output == "")
				{
					
				}
				// if (output == "FIRE_KEYBOARD_EVENT") {
				// System.out.println(output);
				// Thread uiDevice = new Thread(new KeyboardInput());
				// uiDevice.start();
				// my_reason = output;
				// } else {
				// my_reason = "Timer";
				// }
			}
			p.storeIndex(index);
		}

	}

	private void getPriorities(List<Process> procs) 
	{
		Scanner in = new Scanner(System.in);
		try
		{
			for (int i = 0; i < procs.size(); i++)
			{
				System.out.println("Enter a priority for process " + i + "(" + procs.get(i).getClass().getName().replace("processes.", "") + ")" + " 0-10:");
				int p = in.nextInt();
				procs.get(i).setPriority(p);
			}
		}
		catch(Exception the_e)
		{
			System.out.println("Priorities not set because of invalid entry.");
		}
	}

	private ScheduleType getSchedType() {
		Scanner in = new Scanner(System.in);
		ScheduleType rval;
		try {
			System.out
					.print("Enter scheduling system(0:Round-Robin, 1:Priority, 2:Lottery):");
			int priority = Integer.parseInt(in.nextLine());
			switch (priority) {
			case 0:
				rval = ScheduleType.ROUND_ROBIN;
				break;
			case 1:
				rval = ScheduleType.PRIORITY;
				break;
			case 2:
				rval = ScheduleType.LOTTERY;
				break;
			default:
				rval = ScheduleType.ROUND_ROBIN;
				break;

			}
		} catch (Exception the_e) {
			rval = ScheduleType.ROUND_ROBIN;
		}
		return rval;
	}

	/**
	 * Prompts user for choice of scheduler type and process.
	 */
	private List<Process> getProcesses() {
		List<Process> rList = new ArrayList<>();
		Scanner in = new Scanner(System.in);
		try {

			System.out.print("Enter # of Caclulating processes:");
			int calcNum = Integer.parseInt(in.nextLine());
			System.out.print("Enter # of User Interface processes:");
			int uiNum = Integer.parseInt(in.nextLine());
			System.out.print("Enter # of Producer/Consumer pair processes:");
			int pNum = Integer.parseInt(in.nextLine());

			// Add Calc processes
			for (int i = 0; i < calcNum; i++) {
				rList.add(new Calc(1));
			}

			// Add UI processes
			for (int i = 0; i < uiNum; i++) {
				rList.add(new UI(1));
			}

			// Add Prod/Cons pairs
			for (int i = 0; i < pNum; i++) {
				rList.add(new Producer(1));
				rList.add(new Consumer(1));
			}

		} catch (Exception c) {

		}
		return rList;
	}

}
